/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package structures;

import java.util.Iterator;
import music.AbstractNote;
import music.Measure;
import music.Note;
import music.TimeSignature;

/**
 *
 * @author TJ
 */
public class Voice {
    private TimeSignature time;
    private Measure parent;
    private NoteNode head=null,tail=null;
    public Voice(Measure m) {
        parent=m;
        time=m.getTime();
    }
    public void clear() {
        NoteNode h=head;
        tail=head=null;
        if(head!=null) {
            do{
                h=h.next;
                h.prev=null;
                if(h!=null){h.prev.next=null;}
            }while(h!=null);
        }
    }
    public boolean isEmpty(){return head==null;}
    public void addNoteAt(float beat,Note note){
        
        NoteNode h=head;
        if(head==null) {
            tail=head=new NoteNode(beat,note,null,null);
        } else{
            while(h.next!=null && h.beat<beat) {
                
                h=h.next;
            } 
            if(beat>=h.beat && beat<h.data.getLength(time)) {
             h.data=note;   
            } else {
            NoteNode a=new NoteNode(beat,note,h,h.next);
            if(h.next!=null) {h.next.prev=a;}
            else {tail=a;}
            h.next=a;
            }
        }
        note.setMeasure(parent);
    }
    public boolean noteExistsIn(float f) {
        NoteNode h=head;
        while(h!=null && h.beat<=f) {
            if(f>h.beat && f<h.data.getLength(time)+h.beat && !h.data.isRest()){return true;}
            h=h.next;
        }
        return false;
    }
    public boolean noteExistsAt(float f){
        NoteNode h=head;
        while(h!=null && h.beat<=f) {
            if(h.beat==f && !h.data.isRest()){return true;}
            h=h.next;
        }
        return false;
    }
    public Iterator getIterator() {return new VoiceIterator(head);}
    class VoiceIterator implements Iterator{
        NoteNode curr;
        private VoiceIterator(NoteNode head) {
            curr=head;
        }

        @Override
        public boolean hasNext() {
            return curr!=null;
        }

        @Override
        public Object next() {
            Object ret=curr.data;
            curr=curr.next;
            return ret;
        }

        @Override
        public void remove() {
            if(curr!=null){
                if(head==curr) {
                    head=head.next;
                }
                if(tail==curr) {
                    tail=tail.prev;
                }
                if(curr.next!=null)
                    curr.next.prev=curr.prev;
                if(curr.next!=null)
                    curr.prev.next=curr.next;
                }
            }
            
    }
    class NoteNode {
        NoteNode next, prev;
        float beat;
        AbstractNote data;
        NoteNode(float b, AbstractNote d, NoteNode p, NoteNode n) {
            next=n;
            prev=p;
            beat=b;
            data=d;
            d.setBeat(b);
        }
    }
}
